#region Imported Namespaces

using System;
using System.Diagnostics;
using System.Threading;
using Christian.Helle.PocketNews.PocketPC.Controls;
using Christian.Helle.PocketNews.PocketPC.Data;
using Christian.Helle.PocketNews.PocketPC.Diagnostics;
using Christian.Helle.PocketNews.PocketPC.NewsProtocol;

#endregion

namespace Christian.Helle.PocketNews.PocketPC
{
    public class NntpThread : IDisposable
    {
        private readonly frmMain main;
        private Thread thread;

        public NntpThread(frmMain form)
        {
            main = form;
        }

        #region IDisposable Members

        public void Dispose()
        {
            Abort();
        }

        #endregion

        public void LoadArticleHeaders()
        {
            if (thread != null)
                return;
            thread = new Thread(LoadArticleHeadersWorker) {Name = "NntpThread Worker", IsBackground = true};
            thread.Start();
        }

        public void LoadArticleHeadersInCurrentThread()
        {
            LoadArticleHeadersWorker();
        }

        public void Abort()
        {
            if (thread != null)
            {
                thread.Abort();
            }
        }

        private void LoadArticleHeadersWorker()
        {
            if (string.IsNullOrEmpty(Configuration.CurrentNewsgroup))
            {
                thread = null;
                return;
            }

            Cache.ArticleCollection.Clear();
            Cache.NewArticles.Clear();

            if (main != null)
            {
                main.Invoke(
                    main.UpdateNntpStatusDelegate,
                    new object[] {true});

                main.Invoke(
                    main.UpdateStatusBarDelegate,
                    new object[] {"Retrieving headers..."});

                main.Invoke(new EventHandler(main.StartArticleDownloadDelegate));
            }

            try
            {
                using (new WaitCursor())
                {
                    LoadCachedHeaders();
                    DownloadNewHeaders();
                }
            }
            catch (ThreadAbortException)
            {
                if (main != null)
                {
                    main.Invoke(
                        main.UpdateStatusBarDelegate,
                        new object[] {"Process aborted!"});
                }
            }
            catch (Exception e)
            {
                var handler = new DeviceExceptionHandler(e);
                handler.HandleException("Unable to load article header", false);
                Debug.Assert(false, e.Message, e.StackTrace);
            }
            finally
            {
                thread = null;

                if (main != null)
                {
                    main.Invoke(
                        main.UpdateNntpStatusDelegate,
                        new object[] {false});

                    main.Invoke(new EventHandler(main.EndArticleDownloadDelegate));
                }

                if (Cache.NewArticles.Count > 0)
                    DataAccess.Instance.SaveArticlesEx(
                        Cache.NewArticles.ToArray(),
                        Configuration.CurrentNewsgroup);
            }
        }

        private static void LoadCachedHeaders()
        {
            Cache.ArticleCollection.AddRange(
                DataAccess.Instance.GetArticlesEx(
                    Configuration.CurrentNewsgroup,
                    Configuration.MaxCount));
        }

        private void DownloadNewHeaders()
        {
            if (!Connection.VerifyConnection())
                return;

            using (var nntp = new Nntp())
            {
                nntp.EnableEvents = true;
                nntp.OnDownloadHeaderSucceeded += GetHeaderSucceeded;
                nntp.OnDownLoadHeaderOne += nntp_OnDownLoadHeaderOne;

                nntp.Connect(Configuration.NntpServer);

                if (!nntp.IsConnected)
                    return;

                var group = DataAccess.Instance.GetNewsgroupDetails(Configuration.CurrentNewsgroup);
                if (group == null)
                    return;

                nntp.SelectGroup(Configuration.CurrentNewsgroup);

                if (group.Low != 0 && group.High != 0)
                {
                    if (group.High < nntp.CurrentNewsgroup.High)
                        nntp.DownloadHeaders(group.High, nntp.CurrentNewsgroup.High);
                }
                else
                    nntp.DownloadHeaders();

                if (group.High != nntp.CurrentNewsgroup.High)
                    DataAccess.Instance.UpdateNewsgroupDetails(nntp.CurrentNewsgroup);
            }
        }

        private void GetHeaderSucceeded(object sender, EventArgs e)
        {
            if (main != null)
            {
                main.Invoke(
                    main.UpdateStatusBarDelegate,
                    new object[]
                        {
                            string.Format(
                                "{0} Posts",
                                Cache.ArticleCollection.Count)
                        });
            }
        }

        private static void nntp_OnDownLoadHeaderOne(object sender, ArticleHeader header)
        {
            if (!Cache.NewArticles.Contains(header))
                Cache.NewArticles.Insert(0, header);

            if (!Cache.ArticleCollection.Contains(header))
                Cache.ArticleCollection.Insert(0, header);
        }
    }
}